#include <stdio.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include "toolbox2.h"
#include "string.h"
#include "cmath"
#include "time.h"
#include <QtDebug>


using namespace std;

bool get_accession(char * header, char *& tag);
bool check_file(char * file_name);
bool doesnt_overlap(int xS, int xE, int yS, int yE, int buffer);
bool sequence_type(char * seq, int len);


Toolbox2::Toolbox2()
{
    matrix_vals = NULL;
}

Toolbox2::Toolbox2(char * mono_file, char * sequence_file)
{
    runMode = 0;
}


Toolbox2::Toolbox2(char * sequence_file)
{
    runMode = 1;
}


Toolbox2::~Toolbox2()
{
    mutex.lock();
    if(mono!=NULL)
        delete mono;
    delete sequence;
    if(monoFile!=NULL)
        delete monoFile;
    delete searchFile;
    delete matrix_vals;
    delete results_tag;
    mutex.unlock();
}

void Toolbox2::run()
{
    if (runMode == 0) { //! Monomer Search
        emit calculationStarted();
        start_mono_search();
    }
    if (runMode == 1) {  //! Discovery
        emit calculationStarted();
        qDebug() << "starting discovery";
        start_mono_discovery();
    }
    emit calculationFinished();
}

/*
 * Set the thread run mode.  0: Monomer search // 1: Sequence discovery
 */
void Toolbox2::set_run_mode(int mode) {
    runMode = mode;
}

void Toolbox2::set_mono_search_params(char * mono_file, char * sequence_file, char *out_file, int thresh)
{
    monoFile=new char [300];
    searchFile=new char [300];
    strcpy(monoFile,mono_file);
    strcpy(searchFile,sequence_file);
    threshold = thresh;
    outFile = out_file;
}

void Toolbox2::set_mono_discovery_params(char *sequence_file, char *out_file,
                                         int thresh, int mono_min, int mono_max) {
    searchFile=new char [300];
    outFile = new char[300];
    strcpy(searchFile,sequence_file);
    strcpy(outFile, out_file);
    threshold = thresh;
    //outFile = out_file;
    min_length = mono_min;
    max_length = mono_max;
}

void Toolbox2::start_mono_search()
{
    //get parameters set
    char * file_out=NULL;

    get_parameters_set_search();

    //begin search
    vector<Align> A;
    qstatus = "Calculating...";
    emit statusMessage(qstatus);


    bool find=search(A);
    if(find)
            pruneA(A,buffer);

    if(A.size()<=0)
    {
            cout << "No patterns were found meeting your criteria.\n";
            qstatus = "No patterns found.";
            emit statusMessage(qstatus);
    }
    else
    {
            //get file output name
            get_file_out(file_out);
            write_final_results(A,file_out);
            qstatus = "Search Complete.  Files written.";
            emit statusMessage(qstatus);
    }
    A.clear();
    A.~vector();
    delete file_out;

    /*
    if(!find)
    {
            cout << "No patterns were found meeting your criteria.\n";
            qstatus = "No patterns found.";
            emit statusMessage(qstatus);
    }
    else
    {
            //! get file output name
            //get_file_out(file_out); // disabled temporarily
            //file_out = "test_out";
            file_out = outFile;

            write_all_fasta(file_out,A);
            write_all_xls(file_out,A);
            pruneA(A,buffer);
            write_nonOverlap(file_out,A);
            qDebug() << "Outfile: " << file_out;
            qstatus = "Search Complete.  Files written.";
            emit statusMessage(qstatus);
    }
    delete A;
    delete file_out;
    */
}

void Toolbox2::start_mono_discovery()
{
    int i,j,k;
    ofstream out;

    //get parameters set
    monoFile=NULL;
    char * m;
    bool find;
    char temp[300];
    mono=NULL;
    char * file_out=NULL;

    get_parameters_free_search();

    file_out = outFile;

    /*
    Array_align * best=NULL;
    float best_sum_sim=0;

    Array_align * overall_best=NULL;
    float overall_best_sum_sim=0;

    Array_align * A=NULL;
    */

    vector<Align> a;
    float a_sum_sim;

    vector<Align> * best;
    float * best_sum_sim;

    best=new vector<Align> [max_length-min_length+1];
    best_sum_sim=new float [max_length-min_length+1];
    for(i=0; i<max_length-min_length+1; i++) best_sum_sim[i]=0;

    int overall_index=0;
    float overall_best_sum_sim=0;

    qstatus = "Calculating...";
    emit statusMessage(qstatus);



    for(i=min_length; i<=max_length; i++)
    {
            mono_len=i;
            mono=new char [i+1];

            if(!best[i-min_length].empty())
                    best[i-min_length].clear();

            for(j=0; j<sequence_len-i+1; j++)
            {
                    cout << j << endl;
                    //load sequence into m
                    for(k=0; k<i; k++)
                            mono[k]=sequence[j+k];
                    mono[k]='\0';

                    if(!a.empty())			//if not empty, empty it
                            a.clear();

                    qDebug() << "call search";
                    find=search(a);
                    qDebug() << "end search";
                    if(find)
                            pruneA(a,buffer);

                    if(a.size()>=0)
                    {
                            a_sum_sim=get_sum_sim(a);
                            if( (best[i-min_length].size()==0) || (a_sum_sim>best_sum_sim[i-min_length]) )
                            {
                                    best[i-min_length].swap(a);
                                    best_sum_sim[i-min_length]=a_sum_sim;
                            }
                    }
                    a.clear();
            }//end of loop through sequence

            //now determine if it is the best overall
            if(best[i-min_length].size()>0)		//it's not empty
            {
                    if(best_sum_sim[i-min_length]>overall_best_sum_sim)
                    {
                            overall_best_sum_sim=best_sum_sim[i-min_length];
                            overall_index=i-min_length;
                    }
            }
            delete mono;
            write_temp_results(best[i-min_length], file_out, i);
    }
    write_final_results(best[overall_index],file_out);

    //clean up
    a.clear();
    a.~vector();
    delete file_out;
    for(i=0; i<(max_length-min_length+1); i++)
    {
            best[i].clear();
            best[i].~vector();
    }
    delete best_sum_sim;
    mono=NULL;
    qstatus = "Search Complete.  Files written.";
                emit statusMessage(qstatus);
    }

    /*
    for(i=min_length; i<=max_length; i++)
    {
            mono_len=i;
            mono=new char [i+1];
            best=NULL;
            for(j=0; j<sequence_len-i+1; j++)
            {
                    //load sequence into m
                    for(k=0; k<i; k++)
                            mono[k]=sequence[j+k];
                    mono[k]='\0';
                    A=NULL;

                    find=search(A);

                    qDebug() << "done search";

                    if(find)
                    {
                        qDebug() << "prune";
                            pruneA(A,buffer);
                            qDebug() << "done prune";

                            //check if best
                            if(best==NULL)
                            {
                                    //put it in
                                    best=new Array_align(A);
                                    best_sum_sim=best->get_sum_sim();
                            }
                            else
                            {
                                    if(A->get_sum_sim()>best_sum_sim)
                                    {
                                            //new best put in
                                            delete best;
                                            best=new Array_align(A);
                                            best_sum_sim=best->get_sum_sim();
                                    }
                            }
                    }
                    delete A;
                    qDebug() << "j: " << j;
            }//end of loop through sequence
            qDebug() << "done loop";

            if(best!=NULL)
            {
                    //write out best for size
                    write_best_size(file_out,best);

                    //determine if best for this size is best overall
                    if(overall_best==NULL)
                    {
                            //put it in
                            overall_best=new Array_align(best);
                            overall_best_sum_sim=overall_best->get_sum_sim();
                    }
                    else
                    {
                            if(best_sum_sim>overall_best_sum_sim)
                            {
                                    //new overall best put in
                                    delete overall_best;
                                    overall_best=new Array_align(best);
                                    overall_best_sum_sim=overall_best->get_sum_sim();
                            }
                    }
            }
            delete best;
    }

    if(overall_best!=NULL)
    {
            //overall gets sent to write
            write_all_fasta(file_out,overall_best);
            write_all_xls(file_out,overall_best);
            pruneA(overall_best,buffer);
            write_nonOverlap(file_out,overall_best);
    }
    qstatus = "Search Complete.  Files written.";
                emit statusMessage(qstatus);

    //delete things -- best, A, overall_best
    delete file_out;
    delete overall_best;

    */



//----------------------------------------------------------------//
//Sort elements in vector of alignments according to the start
//site within the search sequence
//@param a : vector of alignments
//@return bool : true if sorted, false if empty
//----------------------------------------------------------------//
bool Toolbox2::sortVector(vector<Align> &a)
{
        if(a.size()==0)
                return false;

        Align * A;
        int i;
        int min;
        int min_index;
        vector<Align> temp;
        while(a.size()>0)
        {
                for(i=0; i<a.size(); i++)
                {
                        A=new Align(a[i]);
                        if(i==0)
                        {
                                min=A->get_startSeq();
                                min_index=i;
                        }
                        else
                        {
                                if(A->get_startSeq()<min)
                                {
                                        min=A->get_startSeq();
                                        min_index=i;
                                }
                        }
                        delete A;
                }
                A=new Align(a[min_index]);
                temp.push_back(A);
                a.erase(a.begin()+min_index);
                delete A;
        }
        temp.swap(a);
        temp.clear();
        temp.~vector();

        return true;
}

//----------------------------------------------------------------//
//Writes out the final results for a range of values considered
//in a discovery (case 2) search
//@param a : vector of alignments
//@para file : file name to be written to
//@return bool : true if written, false if empty
//----------------------------------------------------------------//
bool Toolbox2::write_final_results(vector<Align> a, char * file)
{
        if(a.size()==0)
                return false;

        ofstream fasta;
        ofstream xls;

        Align * A;

        int i,j,k;
        char indiv_file[255];
        sprintf(indiv_file,"%s_sequences.fasta",file);
        fasta.open(indiv_file);
        sprintf(indiv_file,"%s_sequences.xls",file);
        xls.open(indiv_file);

        xls << "Number\tTag\tStart\tEnd\tSimilarity\tSequence\n";


        sortVector(a);
        for(i=0; i<a.size(); i++)
        {

                A=new Align(a[i]);

                fasta << "> " << i << " " <<  results_tag << " | Start: " << A->get_startSeq() << " | End: ";
                fasta << A->get_endSeq() << " | Similarity: " << setprecision(4) << A->get_valueAlign() << endl;

                xls << i << "\t" <<  results_tag << "\t" << A->get_startSeq() << "\t";
                xls << A->get_endSeq() << "\t" << setprecision(4) << A->get_valueAlign() << "\t";

                k=0;
                for(j=A->get_startSeq()-1; j<=A->get_endSeq()-1; j++)
                {
                        xls << sequence[j];
                        fasta << sequence[j];
                        k++;
                        if(k==70)
                        {
                                fasta << endl;
                                k=0;
                        }
                }
                xls << endl;
                fasta << endl;
                fasta << endl;

                delete A;
        }
        fasta.clear();
        fasta.close();
        xls.clear();
        xls.close();
        return true;
}


//----------------------------------------------------------------//
//Writes out the temporary results for each sequence size within
//the range of values considered in a discovery (case 2) search
//appends to file each time it's called.
//@param a : vector of alignments
//@para file : file name to be written to
//@param size : "monomer" size considered
//@return bool : true if written, false if empty
//----------------------------------------------------------------//
bool Toolbox2::write_temp_results(vector<Align> a, char * file, int size)
{
        if(a.size()==0)
                return false;

        ofstream out;

        Align * A;

        int i,j,k;
        char indiv_file[255];
        sprintf(indiv_file,"%s_temp.txt",file);
        if(size==min_length)
                out.open(indiv_file);
        else
                out.open(indiv_file,ios::app);

        sortVector(a);

        out << "monomer size:\t" << size << endl;
        for(i=0; i<a.size(); i++)
        {
                A=new Align(a[i]);

                out << "> " << i << " " <<  results_tag << " | Start: " << A->get_startSeq() << " | End: ";
                out << A->get_endSeq() << " | Similarity: " << setprecision(4) << A->get_valueAlign() << endl;

                k=0;
                for(j=A->get_startSeq()-1; j<=A->get_endSeq()-1; j++)
                {
                        out << sequence[j];
                        k++;
                        if(k==70)
                        {
                                out << endl;
                                k=0;
                        }
                }
                out << endl;
                out << endl;

                delete A;
        }
        out << endl;
        out.clear();
        out.close();
        return true;
}

//----------------------------------------------------------------//
//Determines the sum of all of the individual alignments in order
//to determine which set of alignments is best
//@param a : vector of alignments
//@return float : sum
//----------------------------------------------------------------//
float Toolbox2::get_sum_sim(vector<Align> & a)
{
        int i;
        float sum=0;
        for(i=0; i<a.size(); i++)
        {
                sum=sum+a[i].get_valueAlign();
        }
        return sum;
}


//----------------------------------------------------------------//
//Determines the start positions for searching thru call and
//initiates the searches
//@param a : vector of alignments
//@return bool : true if an alignment(s) found, false otherwise
//----------------------------------------------------------------//
bool Toolbox2::search(vector<Align> & a)
{
        int *h_locs, *t_locs;
        int num_h_locs, num_t_locs;
        bool loop;
        int pivot_size;

        bool ftype=sequence_type(sequence, sequence_len);
        if(ftype)		//DNA - 4
                pivot_size=pow(mono_len,0.25);
        else			//Default AA - 20
                pivot_size=pow(mono_len,0.05);
        pivot_size++;

        //dislove
        loop=false;
        while(!loop)
                loop=get_locs(h_locs,num_h_locs,t_locs,num_t_locs,pivot_size);

        //do search based on locations
        if(!a.empty())
                a.clear();

        qDebug() << "populate";
        while(!populateA(h_locs, num_h_locs, t_locs, num_t_locs, pivot_size, a))
                pivot_size--;
        qDebug() << "end populate";

        //need to delete heads & tails
        delete h_locs;
        delete t_locs;

        if(a.size()==0) return false;
        else return true;
}


//----------------------------------------------------------------//
//Removes overlapping alignments identified. Uses a greedy approach
//to determine the best set of alignments
//@param a : vector of alignments
//@param buffer : allowable number of residues overlapping
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::pruneA(vector<Align> & a, int buffer)
{
        int i;
        int index;

        vector<Align> tempA;
        Align * A;
        int max_val=0;

        bool loop=true;
        while(loop)
        {
                //get max
                max_val=0;
                for(i=0; i<a.size(); i++)
                {
                        A=new Align(a[i]);
                        if(A->get_valueAlign()>max_val)
                        {
                                max_val=A->get_valueAlign();
                                index=i;
                        }
                        delete A;
                }
                A=new Align(a[index]);
                if(!overlap(tempA,A,buffer))
                        tempA.push_back(a[index]);
                a.erase(a.begin()+index);
                if(a.size()<=0) loop=false;
        }

        a.swap(tempA);
        tempA.clear();
        tempA.~vector();

        return true;
}


//----------------------------------------------------------------//
//Determines if an alignment overlaps with members of an existing
//set
//@param a : vector of set of alignments
//@param element : element
//@param buffer : allowable number of residues overlapping
//@return bool : true if overlaps, false if doesn't
//----------------------------------------------------------------//
bool Toolbox2::overlap(vector<Align> &a, Align * element, int buffer)
{
        int i;
        int es,as,ee,ae;
        es=element->get_startSeq();
        ee=element->get_endSeq();

        Align * A;
        for(i=0; i<a.size(); i++)
        {
                A=new Align(a[i]);
                as=A->get_startSeq();
                ae=element->get_endSeq();
                if( ( (es>(as-buffer))&&(es<(ae+buffer)) ) || ( (as>(es-buffer))&&(as<(ee-buffer)) ) )
                        return true;
                delete A;
        }
        return false;
}

//----------------------------------------------------------------//
//Requests from user the file prefix for all output files generated
//for searches - Case 1
//@param file_name : name of file
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::get_file_out(char *& file_name)
{
        char c;
        char file[300];
        char file1[300];
        char file2[300];
        char file3[300];

        bool writeFlag;
        cout << "Two sequence files will be created. One with all sequences found and one\n";
        cout << "with the best set of non-overlapping sequences. An excel report will\nalso be generated.\n";
        cout << "\nPlease specify a file to write out results (do not include file extension): \n";
        cin >> file;
        cin.clear();

        sprintf(file1,"%s_all.fasta",file);
        sprintf(file2,"%s_nonOverlap.fasta",file);
        sprintf(file3,"%s_all.xls",file);

        writeFlag=true;
        if(!check_file(file1)) {writeFlag=false;}
        else {if(!check_file(file2)) {writeFlag=false;} else{if(!check_file(file3)){writeFlag=false;}}}

        while(!writeFlag)
        {
                cout << endl;
                cout << "A file with that name already exists.\nWould you like to write over the file? (Y/N) ";
                cin>>c;
                cin.clear();
                if( (c=='n') || (c=='N') )
                {
                        cout << "\nPlease specify a file to write out results (do not include file extension): \n";
                        cin >> file;
                        cin.clear();
                        sprintf(file1,"%s_all.fasta",file);
                        sprintf(file2,"%s_nonOverlap.fasta",file);
                        sprintf(file3,"%s_.xls",file);
                        writeFlag=true;
                        if(!check_file(file1)) {writeFlag=false;}
                        else {if(!check_file(file2)) {writeFlag=false;} else{if(!check_file(file3)){writeFlag=false;}}}
                }
                else
                        writeFlag=true;
        }

        if(file_name!=NULL)
        {
                delete file_name;
        }
        file_name=new char [strlen(file)+1];
        strcpy(file_name,file);
        return true;
}

//----------------------------------------------------------------//
//Requests from user the file prefix for all output files generated
//for discovery - Case 2
//@param file_name : name of file
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::get_file_out_free(char *& file_name)
{
        char c;
        char file[300];
        char file1[300];
        char file2[300];
        char file3[300];
        char file4[300];

        bool writeFlag;
        cout << endl;
        cout << "Two sequence files will be created. One with all sequences found and one\n";
        cout << "with the best set of non-overlapping sequences. An excel report will\n";
        cout << "also be generated. In addition, a temporary file will be created which\n";
        cout << "lists the results found for each monomer size in the specified range.\n";
        cout << "\nPlease specify a file to write out results (do not include file extension): \n";
        cin >> file;
        cin.clear();

        sprintf(file1,"%s_all.fasta",file);
        sprintf(file2,"%s_nonOverlap.fasta",file);
        sprintf(file3,"%s_all.xls",file);
        sprintf(file4,"%s_temp.xls",file);				///doesn't check for this file.

        writeFlag=true;
        if(!check_file(file1)) {writeFlag=false;}
        else {if(!check_file(file2)) {writeFlag=false;} else{if(!check_file(file3)){writeFlag=false;}}}

        while(!writeFlag)
        {
                cout << endl;
                cout << "A file with that name already exists.\nWould you like to write over the file? (Y/N) ";
                cin>>c;
                cin.clear();
                if( (c=='n') || (c=='N') )
                {
                        cout << "\nPlease specify a file to write out results (do not include file extension): \n";
                        cin >> file;
                        cin.clear();
                        sprintf(file1,"%s_all.fasta",file);
                        sprintf(file2,"%s_nonOverlap.fasta",file);
                        sprintf(file3,"%s_.xls",file);
                        writeFlag=true;
                        if(!check_file(file1)) {writeFlag=false;}
                        else {if(!check_file(file2)) {writeFlag=false;} else{if(!check_file(file3)){writeFlag=false;}}}
                }
                else
                        writeFlag=true;
        }

        if(file_name!=NULL)
        {
                delete file_name;
        }
        file_name=new char [strlen(file)+1];
        strcpy(file_name,file);
        return true;
}



//----------------------------------------------------------------//
//For each of the pivots, an alignment is determined and scored
//@param h_locs : array of the "head" pivot locations
//@param num_h_locs : number of "head" pivot locations
//@param t_locs : array of the "tail" pivot locations
//@param num_t_locs : number of "tail" pivot locations
//@param pivot_size : size of head/tail pivot sequences
//@param a : vector of alignments
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::populateA(int *& h_locs, int num_h_locs, int *& t_locs, int num_t_locs, int pivot_size, vector<Align> & a)
{
        int i,j;
        char * subseq;
        Matrix2 * m;
        Align * x;
        int pos=0;
        int len;			//length of subsequence to be analyzed

        //heads
        for(i=0; i<num_h_locs; i++)
        {
                if(h_locs[i]+min_length>sequence_len) i=num_h_locs;
                else
                {
                        if(h_locs[i]+max_length<sequence_len) len=max_length;
                        else
                                len=sequence_len-h_locs[i]+1;
                        subseq=new char [len+1];
                        for(j=0; j<len; j++)
                                subseq[j]=sequence[h_locs[i]+j];	//look at sequence after pivot -- head
                        subseq[j]='\0';
                        m=new Matrix2(matrix_vals);
                        m->make_matrices(mono,mono_len,subseq,len,h_locs[i]);	//look at sequence after pivot -- head
                        if(m->get_best_align_score()>(float)threshold)
                        {
                                x=NULL;
                                m->get_alignment(x);
                                a.push_back(x);
                                delete x;
                                pos++;
                        }
                        delete subseq;
                        delete m;
                }
        }

        //tail
        for(i=0; i<num_t_locs; i++)
        {
                if(t_locs[i]-min_length<0) i=num_t_locs;
                else
                {
                        if(t_locs[i]-max_length>0) len=max_length;
                        else
                                len=t_locs[i]+1;
                        subseq=new char [len+1];
                        for(j=0; j<len; j++)
                                subseq[j]=sequence[t_locs[i]-len+1+j];	//look at sequence before pivot -- tail
                        subseq[j]='\0';
                        m=new Matrix2(matrix_vals);
                        m->make_matrices(mono,mono_len,subseq,len,t_locs[i]-len+1);	//look at sequence before pivot -- tail
                        if(m->get_best_align_score()>(float)threshold)
                        {
                                x=NULL;
                                m->get_alignment(x);
                                a.push_back(x);
                                delete x;
                                pos++;
                        }
                        delete subseq;
                        delete m;
                }
        }

        return true;
}

//----------------------------------------------------------------//
//Ids the pivot sequences and their locations
//@param h_locs : array of the "head" pivot locations
//@param num_h_locs : number of "head" pivot locations
//@param t_locs : array of the "tail" pivot locations
//@param num_t_locs : number of "tail" pivot locations
//@param pivot_size : size of head/tail pivot sequences
//@return bool : true if pivots are found, false otherwise
//----------------------------------------------------------------//
bool Toolbox2::get_locs(int *& head_locs, int & num_head_locs, int *& tail_locs, int & num_tail_locs, int & pivot_size)
{
        int i,j,p;

        char * head, * tail;

        //determine the head and tail sequences
        head=new char [pivot_size+1];
        tail=new char [pivot_size+1];
        for(i=0; i<pivot_size; i++)
        {
                head[i]=mono[i];
                tail[i]=mono[mono_len-pivot_size+i];
        }
        head[i]='\0';
        tail[i]='\0';

        //find the locations
        bool match;
        num_head_locs=0;
        num_tail_locs=0;

        //head
        for(i=0; i<sequence_len-pivot_size+1; i++)
        {
                match=true;
                for(j=0; j<pivot_size; j++)
                {
                        if(head[j]!=sequence[i+j])
                        {
                                match=false;
                                j=pivot_size;
                        }
                }
                if(match)
                        num_head_locs++;
        }
        if(num_head_locs==0)
        {
                head_locs=NULL;
                num_head_locs=0;
        }
        else
        {
                head_locs=new int [num_head_locs];
                p=0;
                for(i=0; i<sequence_len-pivot_size+1; i++)
                {
                        match=true;
                        for(j=0; j<pivot_size; j++)
                        {
                                if(head[j]!=sequence[i+j])
                                {
                                        match=false;
                                        j=pivot_size;
                                }
                        }
                        if(match)
                        {
                                head_locs[p]=i;
                                p++;
                        }
                }
        }

        //tail
        for(i=0; i<sequence_len-pivot_size+1; i++)
        {
                match=true;
                for(j=0; j<pivot_size; j++)
                {
                        if(tail[j]!=sequence[i+j])
                        {
                                match=false;
                                j=pivot_size;
                        }
                }
                if(match)
                        num_tail_locs++;
        }
        if(num_tail_locs==0)
        {
                tail_locs=NULL;
                num_tail_locs=0;
        }
        else
        {
            qDebug() << "num_tail_locs: " << num_tail_locs;
                tail_locs=new int [num_tail_locs];
                p=0;
                for(i=0; i<sequence_len-pivot_size+1; i++)
                {
                        match=true;
                        for(j=0; j<pivot_size; j++)
                        {
                                if(tail[j]!=sequence[i+j])
                                {
                                        match=false;
                                        j=pivot_size;
                                }
                        }
                        if(match)
                        {
                                tail_locs[p]=i;
                                p++;
                        }
                }
        }

        if( (num_tail_locs==0) && (num_head_locs==0) )
        {
                pivot_size--;
                delete head;
                delete tail;
                return false;
        }
        else
        {
                delete head;
                delete tail;
                return true;
        }
}


//----------------------------------------------------------------//
//Functionality for user to change match, mismatch and gap scores
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::set_matrix_values(float match, float mismatch, float gapSeq, float gapMono)
{
    qDebug() << "set_matrix_values";
    if (matrix_vals == NULL)
        matrix_vals = new float[4];
        matrix_vals[0] = match;
        matrix_vals[1] = mismatch;
        matrix_vals[2] = gapSeq;
        matrix_vals[3] = gapMono;

#ifdef DEBUG
        qDebug() << "matrix vals: ";
        qDebug() << matrix_vals[0];
        qDebug() << matrix_vals[1];
        qDebug() << matrix_vals[2];
        qDebug() << matrix_vals[3];
#endif

        return true;
}

bool Toolbox2::show_matrix_values()
{
	cout << endl;
	cout << "********** ALIGNMENT VALUES **********" << endl;
	cout << "Match: " << matrix_vals[0] << endl;
	cout << "Mismatch: " << matrix_vals[1] << endl;
	cout << "Gap in Search Sequence: " << matrix_vals[2] << endl;
	cout << "Gap in Monomer Sequence: " << matrix_vals[3] << endl;
	cout << "**************************************" << endl;
	cout << endl;
	return true;
}

/**
 * Reads in monomer and sequence files
 * stores in char mono[] and char seq[]
 * Gets header of seq, sets as result tag
 */
bool Toolbox2::get_parameters_set_search()
{
        //char header[300];
	char c;
	int i;
	bool flag;
	ifstream in;

	//intialize
	mono_len=0;
	sequence_len=0;

	//read monomer file
	in.open(monoFile);
	in.getline(header,300,'\n');

	flag=false;
        //! Getting Mono Length
	while(in.peek()!=EOF)
	{
                in >> c;
		mono_len++;
		if( (in.peek()==EOF) && (flag) ) mono_len--;
		if(in.peek()==10) flag=true;
		else flag=false;
	}
	in.clear();
	in.close();

        //! Getting Mono Seq
	mono=new char [mono_len+1];

	in.open(monoFile);
	in.getline(header,300,'\n');
	i=0;
	for(i=0; i<mono_len; i++)
	{
		in>> c;
		if(c<97) mono[i]=c+32;
		else mono[i]=c;
	}
	mono[i]='\0';
	in.clear();
	in.close();
	cout << "File '" << monoFile << "' read." << endl;
	cout << header << endl;
	cout << endl;


	//read sequence file
	in.open(searchFile);
	in.getline(header,300,'\n');
	flag=false;
	while(in.peek()!=EOF)
	{
		in>> c;
		sequence_len++;
		if( (in.peek()==EOF) && (flag) ) sequence_len--;
		if(in.peek()==10) flag=true;
		else flag=false;
	}
	in.clear();
	in.close();

	sequence=new char [sequence_len+1];

	in.open(searchFile);
	in.getline(header,300,'\n');
	i=0;
	while(in.peek()!=EOF)
	{
		in>> c;
		if(c<97) sequence[i]=c+32;
		else sequence[i]=c;
		i++;
	}
	sequence[i]='\0';
	in.clear();
	in.close();
	cout << "File '" << searchFile << "' read." << endl;
	cout << header << endl;
	cout << endl;

	results_tag=NULL;
	flag=false;


        get_accession(header,results_tag);

        qDebug() << "header: " << header;

        QString rTag = results_tag;
        emit resultsTag(rTag);

        pauseThread();

        set_results_tag(header);

#ifdef DEBUG
        qDebug() << "threshold: " << threshold;
#endif

        int t = threshold;
        set_threshold(t);

        //! set min and maxs
	set_mins_maxs();
	show_param_vals();
        //set_matrix_values();

	return true;
}

bool Toolbox2::get_parameters_free_search()
{
	char header[300];
	char c;
	int i;
	bool flag;
	ifstream in;

	//intialize
	sequence_len=0;

	//read sequence file
	in.open(searchFile);
	in.getline(header,300,'\n');
	while(in.peek()!=EOF)
	{
		in>> c;
		sequence_len++;
	}
	in.clear();
	in.close();

	sequence=new char [sequence_len+1];

	in.open(searchFile);
	in.getline(header,300,'\n');
	i=0;
	while(in.peek()!=EOF)
	{
		in>> c;
		if(c<97) sequence[i]=c+32;
		else sequence[i]=c;
		i++;
	}
	sequence[i]='\0';
	in.clear();
	in.close();
	cout << "File '" << searchFile << "' read." << endl;
	cout << header << endl;
	cout << endl;

	results_tag=NULL;
	flag=false;
        /*if(get_accession(header,results_tag))
	{
		cout << "The results tag is set to be '" << results_tag << "'." << endl;
		cout << "Is this the tag you would like to use? (Y/N) ";
		cin >> c;
		cin.clear();
		if( !((c=='Y') || (c=='y')) )
		{
			cout << "Enter a results tag. Hit enter when done. ";
			cin >> header;
			cin.clear();
			set_results_tag(header);
		}
	}
	else
	{
			cout << "Enter a results tag. Hit enter when done. ";
			cin >> header;
			cin.clear();
			set_results_tag(header);
	}

	cout << endl;
        */
        get_accession(header,results_tag);
        QString rTag = results_tag;
        emit resultsTag(rTag);
        pauseThread();
        set_results_tag(header);

	flag=false;
        /*
	while(!flag)
	{
		cout << "What is the minimum threshold for the search (integer value)? ";
		cin >> i;
		flag=set_threshold(i);
        }*/
        int t = threshold;
        set_threshold(t);

	//set min and maxs
        //get_range();
        //show_param_vals();
        //! TODO FIXXXXXXX
        //set_matrix_values();

	return true;
}

//----------------------------------------------------------------//
//Requests range of monomer sizes to be considered from user for
//search with just a search sequence provided - Case 2
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::get_range()
{
	bool run=true;
	int min,max;
	while(run)
	{
		cout << endl;
		cout << "What is the minimum size monomer to search for: ";
		cin>>min;
		cin.clear();
		cout << endl;
		cout << "What is the maximum size monomer to search for: ";
		cin>>max;
		cin.clear();
		cout << endl;
		if(min>max)
		{
			cout << endl;
			cout << "The minimum size cannot be smaller than the maximum.\nTry again.\n";
		}
		else
		{
			if( (min<0) || (max<0) )
			{
				cout << endl;
				cout << "Please enter positive values.\nTry again.\n";
			}
			else
				run=false;
		}
	}
	min_length=min;
	max_length=max;
	return true;
}


//----------------------------------------------------------------//
//Sets range of monomer sizes to be considered based on threshold
//defined by user
//this is only for searches in which the monomer is supplied
//@return bool : true
//----------------------------------------------------------------//
bool Toolbox2::set_mins_maxs()
{
	//this is only for searches in which the monomer is supplied

	//set min_length
	float temp=(float)threshold/100.0;
	temp=temp*(float)mono_len;
	min_length=temp;
	if((float)min_length < temp)
		min_length++;
	
	//set max_length
	temp=(float)threshold/100.0;
	temp=(float)mono_len/temp;
	max_length=temp;
	while( ((float)mono_len/(float)(1.0+max_length))>=((float)threshold/100.0) )
		max_length++;
	if(max_length>sequence_len)
		max_length=sequence_len;
	return true;
}

//----------------------------------------------------------------//
//Sets threshold value from user
//@param t : value set by user
//@return bool : true if valid threshold value, false otherwise
//----------------------------------------------------------------//
bool Toolbox2::set_threshold(int t)
{
	if( (t>0) && (t<101) )
	{
		threshold=t;
		return true;
	}
	else
	{
		cout << "The threshold value must be a positive number." << endl;
		return false;
	}
}



bool Toolbox2::get_results_tag(char *& tag)
{
	if(tag!=NULL)
		delete tag;
	tag=new char [strlen(results_tag)];
	strcpy(tag,results_tag);
	return true;
}

bool Toolbox2::set_results_tag(char * tag)
{
	if(results_tag!=NULL)
		delete results_tag;
	results_tag=new char [strlen(tag)];
	strcpy(results_tag,tag);
	return true;
}

bool Toolbox2::show_param_vals()
{
	cout << endl;
	cout << "********** PARAMETER VALUES **********" << endl;

	if(monoFile==NULL)
		cout << "MONOMER Sequence Length: " << "N/A" << endl;
	else
		cout << "MONOMER Sequence Length: " << mono_len << endl;
	cout << "SEARCH Sequence Length: " << sequence_len << endl;
	cout << "Threshold: " << threshold << endl;
	cout << "Max Sequence Length: " << max_length << endl;
	cout << "Min Sequence Length: " << min_length << endl;
	cout << "**************************************" << endl;
	cout << endl;
	return true;
}

//----------------------------------------------------------------//
//Gets accession number from header line of FASTA file
//@param header : header line from the FASTA file
//@param tag : reference to where the tag will be stored
//@return bool : true
//----------------------------------------------------------------//
bool get_accession(char * header, char *& tag)
{
        char * pch;
        char * pchEnd;
        int i, start;

        pch=strchr(header,'|');	//first occurence after gi
        if(pch==NULL)
                return false;
        pch=strchr(pch+1,'|');	//second pipe
        if(pch==NULL)
                return false;
        pch=strchr(pch+1,'|');	//third pipe
        if(pch==NULL)
                return false;
        pchEnd=strchr(pch+1,'|');	//forth pipe
        if(pchEnd==NULL)
                return false;
        if(tag!=NULL)
                delete tag;
        tag=new char [(pchEnd-header)-(pch-header)];

        start=pch-header+1;
        for(i=start; i<pchEnd-header; i++)
                tag[i-start]=header[i];
        tag[i-start]='\0';

        return true;
}



//----------------------------------------------------------------//
//Determines if the a file exists
//@param file_name : file name
//@return bool : true if doesn't exist, false if already exists
//----------------------------------------------------------------//
bool check_file(char * file_name)
{
    //cbun: had to change this because ios::nocreate is deprecated
    // and not available in <fstream>
        ifstream in;
        in.open(file_name,ios::in);
        if(!in)
        {
                in.clear();
                in.close();
                return true;
        }
        else
        {
                in.clear();
                in.close();
                return false;
        }
}

//----------------------------------------------------------------//
//Determines if two ranges overlap
//@param xS : start of range x
//@param xE : end of range x
//@param yS : start of range x
//@param yE : end of range x
//@param buffer : allowable overlap
//@return bool : true if don't overlap, false if they do
//----------------------------------------------------------------//
bool doesnt_overlap(int xS, int xE, int yS, int yE, int buffer)
{
        //returns true if they DON'T overlap
        //returns false if they DO overlap
        if((xE-buffer)<yS) return true;
        if((xS+buffer)>yE) return true;
        return false;
}

void Toolbox2::pauseThread()
{
    isPaused = true;
    while (true) {
        mutex.lock();
        if (isPaused){
            wcondition.wait(&mutex);

        }

        if (!isPaused){
            wcondition.wakeAll();
            break;
        }
        mutex.unlock();
    }
}

void Toolbox2::unpauseThread()
{
    isPaused = false;
    wcondition.wakeAll();
}

//----------------------------------------------------------------//
//Determines if sequence is DNA or RNA
//@param seq : sequence
//@param len : sequence length
//@return bool : true if DNA, false if not
//----------------------------------------------------------------//
bool sequence_type(char * seq, int len)
{
        int i;
        int v[5];
        for(i=0; i<5; i++) v[i]=0;
        for(i=0; i<len; i++)
        {
                switch(seq[i]){
                case 'a': v[0]++; break;
                case 't': v[1]++; break;
                case 'c': v[2]++; break;
                case 'g': v[3]++; break;
                default: v[4]++;
                }
        }
        if( (v[4] < v[0]) || (v[4] < v[2]) )
                return true;		//probably DNA
        else
                return false;
}
